package com.youhui.weixin.service;

import com.google.gson.Gson;
import com.youhui.weixin.common.MythConfig;
import com.youhui.weixin.common.exception.LoadFileException;
import com.youhui.weixin.common.exception.MythException;
import com.youhui.weixin.common.info.MythExceptionList;
import com.youhui.weixin.service.task.SaveExcelDataTask;
import com.youhui.weixin.utils.PropertiesLoad;
import com.youhui.weixin.utils.excel.*;
import lombok.extern.log4j.Log4j;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.FileInputStream;
import java.util.*;
import java.util.concurrent.Future;

/**
 * Created by https://github.com/kuangcp on 17-10-9  下午5:02
 */
@Service
@Log4j
public class ExcelRedisService {

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    SaveExcelDataTask saveExcelDataTask;
    @Autowired
    DealType dealType;

    private ReadExcel excel = new ReadExcel();
    private HashOperations<String, String, String> hash;

    /**
     * 从配置文件初始化于redis
     * @throws LoadFileException 配置文件加载问题
     */
    private void initExcelConfig() throws LoadFileException {
        HashOperations<String, String, String> hash = stringRedisTemplate.opsForHash();
        String test = hash.get(MythConfig.EXCEL_READ_DEFINE, "name");
        if(test == null) {
            Properties mapping = PropertiesLoad.loadConfig(MythConfig.EXCEL_INIT_PROPERTIES);
            for (Object key : mapping.keySet()) {
                hash.put(MythConfig.EXCEL_READ_DEFINE, key.toString(), mapping.getProperty(key.toString()));
            }
        }
    }

    /**
     * 将上传文件的流直接进行读取转换
     */
    public void readExcel(FileInputStream inputStream, String adminId) throws MythException {
        ExcelData data = excel.readFileInputStream(inputStream);
        readDataToDB(data, adminId);
    }

    public void readExcel(String path, String adminId) throws MythException {
        ExcelData data = excel.readFile(path);
        readDataToDB(data, adminId);

    }

    /**
     * 重写，使用线程池
     * @param data Excel数据
     * @throws MythException 可能的异常：线程
     */
    private void readDataToDB(ExcelData data, String adminId) throws MythException {
        log.info("进入处理Excel，开始调用多线程");
        initExcelConfig();
        HashOperations<String, String, String> hash = stringRedisTemplate.opsForHash();
        Set<String> result = hash.keys(MythConfig.EXCEL_READ_DEFINE);
        int rows = data.getRows();
        int index = 1;
        int endIndex;
        int lengths = rows/MythConfig.CORE_POOL_SIZE + 1;
        for(int i=0; i<MythConfig.CORE_POOL_SIZE; i++){
            endIndex = index+lengths;
            if ((endIndex)>rows){
                endIndex = rows;
            }
            // 采用异步方法进行执行处理分类
            saveExcelDataTask.saveDataToDB(data, index, endIndex, result, hash, adminId);
//            Future<String> future =  saveExcelDataTask.saveDataToDB(data, index, endIndex, result, hash);
//            try {
//                if(future!=null && future.get() != null){
//                    throw new MythException(MythExceptionList.MULTI_READ_EXCEL_EXCEPTION, ExcelRedisService.class);
//                }
//            } catch (Exception e) {
//                e.printStackTrace();
//                throw new MythException(MythExceptionList.MULTI_READ_EXCEL_EXCEPTION, e, ExcelRedisService.class);
//            }
            index = endIndex+1;
        }
        dealType.flushMapCache();
        log.info("完成一次Excel导入");
    }

    // 原先的一个单线程的处理
//    /**
//     * @param data 将Excel读取出来的数据存入Mysql 以及 Redis中去
//     * @throws MythException 各种异常 JSON Mysql
//     */
//    private void readDataToDB(ExcelData data) throws MythException {
//        initExcelConfig();
//        HashOperations<String, String, String> hash = stringRedisTemplate.opsForHash();
//        Map<String, Object> map = new HashMap<>();
//        Set<String> result = hash.keys(MythConfig.EXCEL_READ_DEFINE);
//        Object temp;
//        log.info("开始时间 行"+data.getRows());
//
//        for (int row=1;row<=data.getRows();row++){
//            for(String key:result){
//                temp = data.getContents().get(Position.init(row, readColNum(hash.get(MythConfig.EXCEL_READ_DEFINE, key))));
//                if (temp==null || "".equals(temp) || " ".equals(temp) || "无".equals(temp)) {
//                    map.put(key,null);
//                }else{
//                    readData(map, key, temp);
//                }
//            }
//            // 过滤掉没有优惠券的商品
//            if(map.get("mainKey")==null){
//                // 不做处理
//                map.clear();
//            }else{
//                Goods goods = (Goods) ReflectUtils.mapToEntity(map, Goods.class.getName());
//                goods.setImportTime(new Date());
//
//                // 保存到redis中去
//                try {
//                    goods.setTypeId(dealType.handle(goods.getName()));
//                    // json的字段过滤
//                    hash.put(MythConfig.GOODS_KEY, goods.getGoodsId().toString(), gson.toJson(goods));
//                } catch (UnsupportedEncodingException e) {
//                    throw new MythException(MythExceptionList.PARSE_TYPE_EXCEPTION, e, ExcelRedisService.class);
//                }
////                log.info(goods.toString());
////                goodsDao.save(goods);
////                saveExcelDataTask.save(goods);
//            }
//        }
//        log.info("循环结束");
//    }
//
//    /**
//     * 将配置文件中数据进行转换
//     * @param col 配置数据 字母
//     * @return 实际列数
//     */
//    private int readColNum(String col){
//        col = col.trim();
//        char target = col.toCharArray()[0];
//        return target-'A'+1;
//    }
//
//    /**
//     * 将配置文件中定义的列，全部自行转换 得到正确类型 放入map
//     * @param map 缓存映射
//     * @param key 键
//     * @param object 值
//     */
//    private void readData(Map<String, Object> map, String key, Object object) throws MythException {
//        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
//        if("goodsId".equals(key)){
//            map.put(key, Long.valueOf(object.toString()));
//        }else if("discount".equals(key)) {
//            String[] names = object.toString().split("减");
//            String discount;
//            if (names.length > 1) {
//                discount = names[1].split("元")[0];
//            }else{
//                names = object.toString().split("元");
//                discount = names[0];
//            }
//            map.put(key, Integer.parseInt(discount));
//        }else if("alreadyBuy".equals(key)){
//            map.put(key, Integer.valueOf(object.toString()));
//        }else if("price".equals(key)){
//            map.put(key, Float.valueOf(object.toString()));
//        }else if("startTime".equals(key) || "endTime".equals(key)){
//            try {
//                map.put(key, simpleDateFormat.parse(object.toString()));
//            } catch (ParseException e) {
//                throw new MythException(MythExceptionList.PARSE_TYPE_EXCEPTION, e, ExcelRedisService.class);
//            }
//        }else{
//            map.put(key, object.toString());
//        }
//    }
    /**
     * 获取redis中hash类型的数据
     * @param mainKey 主要的key
     * @return 返回map数据
     */
    public Map<String, String> readHashInRedis(String mainKey){
        Map<String, String> map = new HashMap<>();
        hash  = stringRedisTemplate.opsForHash();
        Set<String> keys = hash.keys(mainKey);
        for (String key:keys){
            map.put(key, hash.get(mainKey, key));
        }
        return map;
    }
    public void deleteHashKey(String mainKey){
        stringRedisTemplate.delete(mainKey);
    }
    public void writeHashInRedis(String mainKey, String key, String value){
        hash  = stringRedisTemplate.opsForHash();
        hash.put(mainKey, key, value);
    }
}
